﻿using MongoDB.Driver;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Doolin.MongoRepository.Commons
{
  public interface IMongoRepositoryAsync
  {
    /// <summary>
    /// A generic GetOne method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    Task<TEntity> GetOneAsync<TEntity>(string id) where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic GetOne method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    Task<TEntity> GetOneAsync<TEntity>(FilterDefinition<TEntity> filter) where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic get many method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="ids"></param>
    /// <returns></returns>
    Task<List<TEntity>> GetManyAsync<TEntity>(IEnumerable<string> ids) where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic get many method with filter
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="ids"></param>
    /// <returns></returns>
    Task<List<TEntity>> GetManyAsync<TEntity>(FilterDefinition<TEntity> filter) where TEntity : IMongoEntity, new();

    /// <summary>
    /// GetMany with filter and projection
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="filter"></param>
    /// <returns>A cursor for the query</returns>
    IFindFluent<TEntity, TEntity> FindCursorAsync<TEntity>(FilterDefinition<TEntity> filter) where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic get all method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <returns></returns>
    Task<List<TEntity>> GetAllAsync<TEntity>() where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic Exists method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    Task<bool> ExistsAsync<TEntity>(string id) where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic count method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    Task<long> CountAsync<TEntity>(string id) where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic count method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    Task<long> CountAsync<TEntity>(FilterDefinition<TEntity> filter) where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic Add One method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="item"></param>
    /// <returns></returns>
    Task AddOneAsync<TEntity>(TEntity item) where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic delete one method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="id"></param>
    /// <returns></returns>
    Task DeleteOneAsync<TEntity>(string id) where TEntity : IMongoEntity, new();

    /// <summary>
    /// A generic delete many method
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="ids"></param>
    /// <returns></returns>
    Task<long> DeleteManyAsync<TEntity>(IEnumerable<string> ids) where TEntity : IMongoEntity, new();

    #region Update
    /// <summary>
    /// UpdateOne by id
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="id"></param>
    /// <param name="update"></param>
    /// <returns></returns>
    Task UpdateOneAsync<TEntity>(string id, UpdateDefinition<TEntity> update) where TEntity : IMongoEntity, new();

    /// <summary>
    /// UpdateOne with filter
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="filter"></param>
    /// <param name="update"></param>
    /// <returns></returns>
    Task UpdateOneAsync<TEntity>(FilterDefinition<TEntity> filter, UpdateDefinition<TEntity> update) where TEntity : IMongoEntity, new();

    /// <summary>
    /// UpdateMany with Ids
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="id"></param>
    /// <param name="update"></param>
    /// <returns></returns>
    Task<long> UpdateManyAsync<TEntity>(IEnumerable<string> ids, UpdateDefinition<TEntity> update) where TEntity : IMongoEntity, new();

    /// <summary>
    /// UpdateMany with filter
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="filter"></param>
    /// <param name="update"></param>
    /// <returns></returns>
    Task<long> UpdateManyAsync<TEntity>(FilterDefinition<TEntity> filter, UpdateDefinition<TEntity> update) where TEntity : IMongoEntity, new();
    #endregion Update

    #region Find And Update

    /// <summary>
    /// GetAndUpdateOne with filter
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="filter"></param>
    /// <param name="update"></param>
    /// <param name="options"></param>
    /// <returns></returns>
    Task<TEntity> GetAndUpdateOne<TEntity>(FilterDefinition<TEntity> filter, UpdateDefinition<TEntity> update, FindOneAndUpdateOptions<TEntity, TEntity> options) where TEntity : IMongoEntity, new();

    #endregion Find And Update
  }
}
